/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>


#include "ohos_bt_gatt.h"
#ifdef ADAPTER_BT_L0_SUPPORT
#include "ohos_bt_log.h"
#else
#include "log.h"
#endif

#include "ohos_bt_gap.h"

uint8_t g_adv_status=0;
uint8_t g_io_cap_mode = 0;
uint8_t g_sc_mode = 0;
gap_ble_callbacks_t g_gapCallback = {
    .ble_enable_cb          = ble_enable_callback,
    .ble_disable_cb         = ble_disable_callback,
    .set_adv_data_cb        = set_adv_data_callback,
    .set_adv_param_cb       = set_adv_param_callback,
    .set_scan_param_cb      = NULL,
    .start_adv_cb           = start_adv_callback,
    .stop_adv_cb            = stop_adv_callback,
    .scan_result_cb         = NULL,
    .conn_state_change_cb   = conn_state_change_callback,
};

BtGattCallbacks *g_bleGapCb = NULL;
BtGattServerCallbacks *g_bleGattsCb = NULL;
BdAddr g_bdAddr = {0};


int BleGattsSetEncryption(BdAddr bdAddr, BleSecAct secAct) {
  LOG_PRINT( "[iot_ble_lite_log] BleGattsSetEncryption  ");
  gap_ble_sec_params_t sec_params = {0};
  sec_params.bondable = 1;
  sec_params.io_capability = g_io_cap_mode;
  sec_params.sc_enable = 1;
  sec_params.sc_mode = secAct;
  // sec_params.sc_mode = g_sc_mode;
  LOG_PRINT("io_capability:%d g_sc_mode:%d",g_io_cap_mode ,g_sc_mode);
  int ret = gap_ble_set_sec_param(&sec_params);
  if (ret != 0) {
      LOG_PRINT("gap_ble_set_sec_param fail, ret:%d.", ret);
  }
  return ret;
}

int BleGattSecurityRsp(BdAddr bdAddr, bool accept) {
  LOG_PRINT( "[iot_ble_lite_log] BleGattSecurityRsp");
  return 0;
}

int BleSetSecurityAuthReq(BleAuthReqMode mode) {
    LOG_PRINT( "[iot_ble_lite_log] BleSetSecurityAuthReq %u",mode);
    g_sc_mode = mode;
    return  0;
}

int BleSetSecurityIoCap(BleIoCapMode mode) {
    LOG_PRINT( "[iot_ble_lite_log] BleSetSecurityIoCap  %u",mode);
    g_io_cap_mode = mode;
    return  0;
}


// 设置广播数据
int BleStartAdvEx(int *advId, const StartAdvRawData rawData, BleAdvParams advParam) {
    LOG_PRINT( "[iot_ble_lite_log] BleStartAdvEx advId:%u g_adv_status:%u", *advId, g_adv_status);
    errcode_t ret = ERRCODE_BT_FAIL;
    
    if (g_adv_status == 0) {
      *advId = BLE_ADV_HANDLE_DEFAULT;
      LOG_PRINT(" StartAdvRawData advDataLen:%u rspDataLen:%u", rawData.advDataLen, rawData.rspDataLen);
      ret = BleSetAdvParam(BLE_ADV_HANDLE_DEFAULT, &advParam);
      if (ret != ERRCODE_BT_SUCCESS) {
          LOG_PRINT(" BleStartAdvEx gap_ble_start_adv error.");
          return ret;
      }
      ret = BleSetAdvData(BLE_ADV_HANDLE_DEFAULT, rawData);
      if (ret != ERRCODE_BT_SUCCESS) {
          LOG_PRINT(" BleStartAdvEx gap_ble_set_adv_data error.");
          return ret;
      }
      ret = gap_ble_start_adv(BLE_ADV_HANDLE_DEFAULT);
      if (ret != ERRCODE_BT_SUCCESS) {
           LOG_PRINT("BleStartAdvEx gap_ble_start_adv error.");
           return ret;
       }
      g_adv_status = 1;
      LOG_PRINT(" BleStartAdvEx gap_ble_start_adv success ");
    } else {
        LOG_PRINT(" BleStartAdvEx already adv.");
        return ret;
    }
    return ret;
}

int BleSetAdvData(int advId, const StartAdvRawData data)
{    
    HILOG_DEBUG("[bluetooth] BleSetAdvData");
    gap_ble_config_adv_data_t advData = {0};
    advData.adv_data = data.advData;
    advData.adv_length = data.advDataLen;
    advData.scan_rsp_data = data.rspData;
    advData.scan_rsp_length = data.rspDataLen;

    int ret = gap_ble_set_adv_data(advId, &advData);
    if (ret != ERRCODE_BT_SUCCESS) {
        HILOG_DEBUG( "BleSetAdvData ret:%u",ret);
    }
    return ret;
}

int BleSetAdvParam(int advId, const BleAdvParams *param)
{
    errcode_t ret = ERRCODE_BT_FAIL;
    gap_ble_adv_params_t advParams = {0};

    HILOG_DEBUG("[bluetooth] BleStartAdv advId:%u",advId);

    advParams.min_interval         = param->minInterval;
    advParams.max_interval         = param->maxInterval;
    advParams.duration             = param->duration;
    advParams.channel_map          = param->channelMap;
    advParams.adv_type             = param->advType;
    advParams.adv_filter_policy    = param->advFilterPolicy;
    advParams.peer_addr.type       = param->peerAddrType;
    advParams.own_addr.type        = param->ownAddrType;
    advParams.tx_power             = param->txPower;
    (void)memcpy_s(&advParams.peer_addr.addr, BD_ADDR_LEN, param->peerAddr.addr, BD_ADDR_LEN);
    (void)memset_s(&advParams.own_addr.addr, BD_ADDR_LEN, BD_ADDR_LEN);
    ret = gap_ble_set_adv_param(advId, &advParams);
    if (ret != ERRCODE_BT_SUCCESS) {
        HILOG_ERROR("[bluetooth] BleStartAdv Error:%d", ret);
    }
    return ret;
}

int BleStopAdv(int advId)
{
    HILOG_DEBUG("[bluetooth] BleStopAdv advId= %d",advId);
    g_adv_status = 0;
    return gap_ble_stop_adv(advId);
}

void ble_enable_callback(errcode_t status)
{
    HILOG_DEBUG("[bluetooth] ble_enable_callback status:%d.", status);
}

void ble_disable_callback(errcode_t status)
{
    HILOG_DEBUG("[bluetooth] ble_disable_callback status:%d.", status);
}

void set_adv_data_callback(uint8_t adv_id, errcode_t status)
{
    HILOG_DEBUG("[bluetooth] set_adv_data_callback status:%d.", status);
    if(g_bleGapCb->advDataCb != NULL){
        g_bleGapCb->advDataCb(adv_id, status);
    }else{
        HILOG_DEBUG(0,"advDataCb is NULL");  
    }
}

void set_adv_param_callback(uint8_t adv_id, errcode_t status)
{
    HILOG_DEBUG("[bluetooth] set_adv_param_callback adv_id:%d status:%d.", adv_id, status);
}

void start_adv_callback(uint8_t adv_id, adv_status_t status)
{
    HILOG_DEBUG("[bluetooth] start_adv_callback adv_id:%d status:%d.", adv_id, status);

    if (status == ADV_STATUS_ADVERTISING) {
        g_bleGapCb->advEnableCb(adv_id, 0);
    } else {
        g_bleGapCb->advEnableCb(adv_id, OHOS_BT_STATUS_FAIL);
    }
}

void stop_adv_callback(uint8_t adv_id, adv_status_t status)
{
    HILOG_DEBUG("[bluetooth] stop_adv_callback status:%d", status);

    if (status == ADV_STATUS_STOPPED) {
        g_bleGapCb->advDisableCb(adv_id, 0);
    } else {
        g_bleGapCb->advDisableCb(adv_id, OHOS_BT_STATUS_FAIL);
    }
}

void conn_state_change_callback(uint16_t conn_id, bd_addr_t *addr,
    gap_ble_conn_state_t conn_state, gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    HILOG_DEBUG("[bluetooth] conn_state_change_callback "
        "conn_id: %d, status: %d, pair_status:%d, disc_reason:%x",
        conn_id, conn_state, pair_state, disc_reason);

    if (conn_state == GAP_BLE_STATE_CONNECTED) {
        BdAddr bd_addr = {0};
        (void)memcpy_s(bd_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN);
        if (g_bleGattsCb->connectServerCb) {
            g_bleGattsCb->connectServerCb(conn_id, g_server_id, &bd_addr);
        }
    } else if (conn_state == GAP_BLE_STATE_DISCONNECTED) {
        LOG_PRINT("conn_state_change_cb_adapt disconnect.");
        BdAddr bd_addr = {0};
        (void)memcpy_s(bd_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN);
        if (g_bleGattsCb->disconnectServerCb) {
            g_bleGattsCb->disconnectServerCb(conn_id, g_server_id, &bd_addr);
        }
    }
}



int BleGattRegisterCallbacks(BtGattCallbacks *func)
{
    if (func == NULL) {
        HILOG_ERROR("[bluetooth] BleGattRegisterCallbacks func is NULL");
        return -1;
    }
    HILOG_DEBUG("[bluetooth] BleGattRegisterCallbacks");
    g_bleGapCb = func;
    return gap_ble_register_callbacks(&g_gapCallback);
}
